﻿using System;
using System.Collections.Generic;
using System.Linq;
using InvestmentIntelligence.DbModel.Models;
using System.Data.Entity.Infrastructure;

namespace InvestmentIntelligence.Data.Repository.EFImplementation
{
    using System.Data.Entity;

    public class AnalysisGroupRepository : IIPRepository<AnalysisGroup>, IAnalysisGroupRepository
    {
        public new int Add(AnalysisGroup group)
        {
            var testGroup = Get(x => x.Name.Equals(group.Name.Trim(), StringComparison.InvariantCultureIgnoreCase));
            if (testGroup != null)
            {
                return testGroup.Id;
            }
            if (string.IsNullOrWhiteSpace(group.Name))
            {
                throw new ArgumentException("Incorrect name");
            }
            group.Name = group.Name.Trim();
            try
            {
                base.Add(group);
                return group.Id;
            }
            catch (DbUpdateException)
            {

                throw new ArgumentException("Incorrect Name");
            }
        }

        public void Remove(int groupId)
        {
            RunUnitOfWork<AnalysisGroup>(c =>
                              {
                                  var currentGroup =
                                      c.AnalysisGroups.Include("Users").Include("FundBookEntities").Single(x => x.Id == groupId);
                                  c.AnalysisGroups.Remove(currentGroup);
                                  c.SaveChanges();
                                  return null;
                              });
        }

        public List<T> GetListWithFundbooks<T>(Func<IQueryable<AnalysisGroup>, IEnumerable<T>> f)
        {
            return base.GetList(dc => f(dc.Include("FundBookEntities")));
        }

        public List<T> GetListByFundbook<T>(Func<IQueryable<AnalysisGroup>, IEnumerable<T>> f, int fundbookId)
        {
            return
                base.GetList(
                    dc =>
                        f(dc.Include("FundBookEntities").Where(c => c.FundBookEntities.Any(x => x.Id == fundbookId))));
        }

        public List<T> GetListWithUsers<T>(Func<IQueryable<AnalysisGroup>, IEnumerable<T>> f)
        {
            return GetList(dc => f(dc.Include("Users.Contact")));
        }

        public AnalysisGroup Get(int groupId)
        {
            return Get(dc => dc.Include("Users").Single(x => x.Id == groupId));
        }

        public new void Update(AnalysisGroup group)
        {
            RunUnitOfWork(data =>
                      {
                          var currentGroup = data.AnalysisGroups.SingleOrDefault(x => x.Id == group.Id);
                          if (currentGroup == null)
                          {
                              throw new NullReferenceException("Group not exist");
                          }
                          currentGroup.Name = group.Name;
                          data.SaveChanges();
                          return default(AnalysisGroup);
                      });
        }

        public void AttachUserToGroup(int groupId, int userId)
        {
            RunUnitOfWork(data =>
             {
                 var user = data.Users.Single(x => x.Id == userId);
                 var group = data.AnalysisGroups.Include("Users").Single(x => x.Id == groupId);
                 group.Users.Add(user);
                 data.SaveChanges(); return default(AnalysisGroup);
             });
        }

        public void RemoveUserFromGroup(int groupId, int userId)
        {
            RunUnitOfWork(data =>
             {
                 var user = data.Users.Single(x => x.Id == userId);
                 var group = data.AnalysisGroups.Include("Users").Single(x => x.Id == groupId);
                 group.Users.Remove(user);
                 data.SaveChanges(); return default(AnalysisGroup);
             });
        }


        public List<T> GetSharedUsers<T>(int userId, Func<IQueryable<User>, IEnumerable<T>> f)
        {
             return RunUnitOfWork(
                dc =>
                    {
                        var groups = from analysisGroup in dc.AnalysisGroups
                               from user in analysisGroup.Users
                               where user.Id == userId
                               select analysisGroup;
                        return f(groups.SelectMany(c => c.Users).Distinct()).ToList();
                    });
        }
    }
}